#include "LogicSystem.h"
#include"HttpConnection.h"
#include"VerifyGrpc_Client.h"
#include"StatusGrpcClient.h"
#include"RedisMgr.h"
#include"MySqlMgr.h"
LogicSystem::LogicSystem()
{
	RegGet("/get_test", [](std::shared_ptr<HttpConnection> connection) {
		beast::ostream(connection->_response.body()) << "receive get_test req"<<std::endl;

		int i = 0;
		for (auto& elme : connection->_get_params)
		{
			i++;
			beast::ostream(connection->_response.body()) << "params" << i << " key is " << elme.first;
			beast::ostream(connection->_response.body()) << "params" << i << " value is " << elme.second<<std::endl;
		}
		});
	RegPost("/get_varifycode", [](std::shared_ptr<HttpConnection> connection) {
		auto body_str = boost::beast::buffers_to_string(connection->_request.body().data());
		std::cout << "receive body is " << body_str << std::endl;
		Json::Value root;
		Json::Reader reader;
		Json::Value src_root;

		bool parse_success = reader.parse(body_str, src_root);
		if (!parse_success)
		{
			std::cout << "Failed to parse JSON data!" << std::endl;
			root["error"] = ErrorCodes::ERROR_json;
			std::string jsonstr = root.toStyledString();
			beast::ostream(connection->_response.body()) << jsonstr;
			return true;
		}

		if (!src_root.isMember("email"))
		{
			std::cout << "Failed to parse JSON data!" << std::endl;
			root["error"] = ErrorCodes::ERROR_json;
			std::string jsonstr = root.toStyledString();
			beast::ostream(connection->_response.body()) << jsonstr;
			return true;
		}

		auto email = src_root["email"].asString();
		GetVarifyRsp rsp = VerifyGrpc_Client::GetInstance()->GetvarifyCode(email);
		std::cout << "email is " << email << std::endl;

		root["error"] = rsp.error();
		root["email"] = src_root["email"];
		std::string jsonstr = root.toStyledString();
		beast::ostream(connection->_response.body()) << jsonstr;
		return true;
		});

	RegPost("/user_register", [](std::shared_ptr<HttpConnection> connection){
		auto body_str = boost::beast::buffers_to_string(connection->_request.body().data());
		std::cout << "receive body is " << body_str << std::endl;
		connection->_response.set(http::field::content_type, "text/json");
		Json::Value root;
		Json::Reader reader;
		Json::Value src_root;
		bool prase_succsee = reader.parse(body_str, src_root);
		if (!prase_succsee) {
			std::cout << "Failed to parse JSON data!" << std::endl;
			root["error"] = ErrorCodes::ERROR_json;
			std::string jsonstr = root.toStyledString();
			beast::ostream(connection->_response.body()) << jsonstr;
			return true;
		}

		auto email = src_root["email"].asString();
		auto name = src_root["user"].asString();
		auto passwd = src_root["passwd"].asString();
		auto confirm = src_root["confirm"].asString();

		if (passwd != confirm)
		{
			std::cout << "Password Error" << std::endl;
			root["error"] = ErrorCodes::PasswdErr;
			std::string jsonstr = root.toStyledString();
			beast::ostream(connection->_response.body()) << jsonstr;
			return true;
		}

		std::string varify_code;
		bool b_get_varify_ = RedisMgr::GetInstance()->Get(CODEPREFIX+src_root["email"].asString(), varify_code);
		if (!b_get_varify_)
		{
			std::cout << " get varify code expired" << std::endl;
			root["error"] = ErrorCodes::VarifyExpired;
			std::string jsonstr = root.toStyledString();
			beast::ostream(connection->_response.body()) << jsonstr;
			return true;
		}

		if (varify_code != src_root["varifycode"].asString())
		{
			std::cout << " varify code error" << std::endl;
			root["error"] = ErrorCodes::VarifyCodeErr;
			std::string jsonstr = root.toStyledString();
			beast::ostream(connection->_response.body()) << jsonstr;
			return true;
		}

		int uid = MySqlMgr::GetInstance()->RegUser(name,passwd,email);
		if (uid == 0 || uid == -1) {
			std::cout << " user or email exist" << std::endl;
			root["error"] = ErrorCodes::UserExist;
			std::string jsonstr = root.toStyledString();
			beast::ostream(connection->_response.body()) << jsonstr;
			return true;
		}

		root["error"] = 0;
		root["email"] = email;
		root["user"] = name;
		root["uid"] = uid;
		root["passwd"] = passwd;
		root["confirm"] = confirm;
		root["varifycode"] = src_root["varifycode"].asString();
		std::string jsonstr = root.toStyledString();
		beast::ostream(connection->_response.body()) << jsonstr;
		return true;
	});

	RegPost("/reset_pwd", [](std::shared_ptr<HttpConnection> connection) {
		auto body_str = boost::beast::buffers_to_string(connection->_request.body().data());
		std::cout << "receive body is " << body_str << std::endl;
		connection->_response.set(http::field::content_type, "text/json");
		Json::Value root;
		Json::Reader prase;
		Json::Value src_root;
		bool prase_succsee = prase.parse(body_str, src_root);
		if (!prase_succsee)
		{
			std::cout << "Failed to parse JSON data!" << std::endl;
			root["error"] = ErrorCodes::ERROR_json;
			std::string jsonstr = root.toStyledString();
			beast::ostream(connection->_response.body()) << jsonstr;
			return true;
		}
		auto email = src_root["email"].asString();
		auto new_pwd = src_root["passwd"].asString();
		auto user_name = src_root["user"].asString();

		std::string varify_code;
		bool b_get_varify = RedisMgr::GetInstance()->Get(CODEPREFIX + src_root["email"].asString(), varify_code);
		if (!b_get_varify)
		{
			std::cout << " get varify code expired" << std::endl;
			root["error"] = ErrorCodes::VarifyExpired;
			std::string jsonstr = root.toStyledString();
			beast::ostream(connection->_response.body()) << jsonstr;
			return true;
		}
		if (src_root["varifycode"].asString() != varify_code)
		{
			std::cout << " varify code error" << std::endl;
			root["error"] = ErrorCodes::VarifyCodeErr;
			std::string jsonstr = root.toStyledString();
			beast::ostream(connection->_response.body()) << jsonstr;
			return true;
		}

		bool check_email = MySqlMgr::GetInstance()->CheckEmail(user_name,email);
		if (!check_email)
		{
			std::cout << " user email not match" << std::endl;
			root["error"] = ErrorCodes::EmailNotMatch;
			std::string jsonstr = root.toStyledString();
			beast::ostream(connection->_response.body()) << jsonstr;
			return true;
		}


		bool b_up = MySqlMgr::GetInstance()->UpdatePwd(user_name, new_pwd);
		if (!b_up)
		{
			std::cout << " update pwd failed" << std::endl;
			root["error"] = ErrorCodes::PasswdUpFaild;
			std::string jsonstr = root.toStyledString();
			beast::ostream(connection->_response.body()) << jsonstr;
			return true;
		}

		std::cout << "succeed to update password" << new_pwd << std::endl;
		root["error"] = 0;
		root["email"] = email;
		root["user"] = user_name;
		root["passwd"] = new_pwd;
		root["varifycode"] = src_root["varifycode"].asString();
		std::string jsonstr = root.toStyledString();
		beast::ostream(connection->_response.body()) << jsonstr;
		return true;
		});

	RegPost("/user_login", [](std::shared_ptr<HttpConnection> connection) {
		auto body_str = boost::beast::buffers_to_string(connection->_request.body().data());
		std::cout << "revice body is " << body_str << std::endl;
		connection->_response.set(http::field::content_type, "text/json");
		Json::Value root_str;
		Json::Reader prase;
		Json::Value src_root;
		bool pares_success = prase.parse(body_str, src_root);
		if (!pares_success)
		{
			std::cout << "False to prase JSON data!" << std::endl;
			root_str["root"] = ErrorCodes::ERROR_json;
			std::string jsonstr = root_str.toStyledString();
			beast::ostream(connection->_response.body()) << jsonstr;
			return true;
		}

		auto email = src_root["email"].asString();
		auto pwd = src_root["passwd"].asString();

		UserInfo userinfo;

		bool pwd_valid = MySqlMgr::GetInstance()->CheckPwd(email, pwd, userinfo);
		if (!pwd_valid)
		{
			std::cout << "user pwd ont match" << std::endl;
			root_str["error"] = ErrorCodes::PasswdInvalid;
			std::string jsonstr = root_str.toStyledString();
			beast::ostream(connection->_response.body()) << jsonstr;
			return true;
		}	

		auto reply = StatusGrpcClient::GetInstance()->GetChatServer(userinfo.uid);
		if (reply.error())
		{
			std::cout << " grpc get chat server failed, error is " << reply.error() << std::endl;
			root_str["error"] = ErrorCodes::RCP_faild;
			string jsonstr = root_str.toStyledString();
			beast::ostream(connection->_response.body()) << jsonstr;
			return true;
		}
		std::cout << "succeed to load userinfo uid is " << userinfo.uid << std::endl;
		root_str["error"] = 0;
		root_str["user"] = userinfo.name;
		root_str["uid"] = userinfo.uid;
		root_str["token"] = reply.token();
		root_str["host"] = reply.host();
		root_str["port"] = reply.port();
		std::string jsonstr = root_str.toStyledString();
		beast::ostream(connection->_response.body()) << jsonstr;
		return true;
		});
}

bool LogicSystem::HandleGet(std::string path, std::shared_ptr<HttpConnection> con)
{
	if (_get_handlers.find(path) == _get_handlers.end())
	{
		return false;
	}
	_get_handlers[path](con);
	return true;
}

void LogicSystem::RegGet(std::string url, HttpHandler handler)
{
	_get_handlers.insert(make_pair(url, handler));
}

void LogicSystem::RegPost(std::string url, HttpHandler handler)
{
	_post_handlers.insert(make_pair(url, handler));
}

bool LogicSystem::HandlePost(std::string path, std::shared_ptr<HttpConnection> con)
{
	if (_post_handlers.find(path) == _post_handlers.end())
	{
		return false;
	}
	_post_handlers[path](con);
	return true;
}

